#!/usr/bin/env python3 
# -*- coding:utf-8 -*-

import os
from collections import Iterator

# 列表生成式即List Comprehensions，是Python内置的非常简单却强大的可以用来创建list的生成式
# 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
li = list(range(1, 11))
print(li)

# 生成[1x1, 2x2, 3x3, ..., 10x10]
li = [x * x for x in range(1, 11)]
print(li)

"""
 列表生成式时，把要生成的元素x * x放到前面，后面跟for循环，就可以把list创建出来
"""

# 全排列
li = [m + n for m in 'ABC' for n in 'XYZ']
print(li)
"""
等价于 java 的 for 循环嵌套

        List<String> list1 = Arrays.asList("A", "B", "C");
        List<String> list2 = Arrays.asList("X", "Y", "Z");
        List<String> list3 = new ArrayList<>();
        for (String s1 : list1) {
            for (String s2 : list2) {
                list3.add(s1 + s2);
            }
        }
        System.out.println(list3);
        
"""

# 列出当前目录下的所有文件和目录名

print([d for d in os.listdir('.')])

# for循环其实可以同时使用两个甚至多个变量，比如dict的items()可以同时迭代key和value
d = {'x': 'A', 'y': 'B', 'z': 'C'}
for k, v in d.items():
    print(k, v)

# 列表生成式也可以使用两个变量来生成list
# 生成['y=B', 'x=A', 'z=C']
d = [k + "=" + v for k, v in d.items()]
print(d)

# 把一个list中所有的字符串变成小写
stringList = ['Harden', 'Paul', 'KD']
stringList2 = [s.lower() for s in stringList]
print(stringList2)

# --------------------------------------------------
# generator 生成器,generator也是可迭代对象

L = [x * x for x in range(10)]
g = (x * x for x in range(10))

# 创建L和g的区别仅在于最外层的[]和()，L是一个list，而g是一个generator。
# next()函数获得generator的下一个返回值

for i in g:
    print(i)


# ------------------
# 斐波拉契数列用,后一个数是前两个数的和
# 1,1,2,3,5,8,13,21......

def fib(max):
    n, a, b = 0, 0, 1  # n = 0,a = 0,b = 1
    while n < max:
        print(b)
        temp = a
        a = b
        b = temp + b
        # 简化一下  a,b = b,a + b  -> t = (b, a + b),a = t[0],b = t[1]
        n += 1
    return "done"


# -------------------
# yield 关键字
# 如果一个函数定义中包含yield关键字，那么这个函数就不再是一个普通函数，而是一个generator
# generator的函数，在每次调用next()的时候执行，遇到yield语句返回，再次执行时从上次返回的yield语句处继续执行。


def fib2(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b  # generator 遇到 yield 就中断
        a, b = b, a + b
        n = n + 1
    return 'done'


f = fib2(10)
# 通常不用 next() 输出,采用 for 循环输出
"""
for n in f:
    print(n)
"""

# 但是用for循环调用generator时，发现拿不到generator的return语句的返回值。
# 如果想要拿到返回值，必须捕获StopIteration错误，返回值包含在StopIteration的value中

while True:
    try:
        x = next(f)
        print("g:", x)
    except StopIteration as e:
        print('Generator return value:', e.value)
        break

# print(list(range(2)))  # [0,1] 不包括2


# ------------------------------------------------------------------------------------------------------------
# 迭代器
# 可以被next()函数调用并不断返回下一个值的对象称为迭代器：Iterator。
# 使用isinstance()判断一个对象是否是Iterator对象：

print(isinstance((x for x in range(10)), Iterator))  # True

isinstance([], Iterator)  # False
isinstance({}, Iterator)  # False
isinstance('abc', Iterator)  # False

# 生成器都是Iterator对象，但list、dict、str虽然是Iterable，却不是Iterator
# 把list、dict、str等Iterable变成Iterator可以使用iter()函数

isinstance(iter([]), Iterator)  # True
isinstance(iter('abc'), Iterator)  # True

"""
为什么list、dict、str等数据类型不是Iterator?

因为Python的Iterator对象表示的是一个数据流，Iterator对象可以被next()函数调用并不断返回下一个数据，
直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列，但我们却不能提前知道序列的长度，
只能不断通过next()函数实现按需计算下一个数据，所以Iterator的计算是惰性的，只有在需要返回下一个数据时它才会计算

凡是可作用于for循环的对象都是Iterable类型；

凡是可作用于next()函数的对象都是Iterator类型，它们表示一个惰性计算的序列；

集合数据类型如list、dict、str等是Iterable但不是Iterator，不过可以通过iter()函数获得一个Iterator对象。

"""
